/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sle_connect_proxy.h"
#include "sle_hilog.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {
int32_t SleConnectProxy::InnerTransact(
    uint32_t code, MessageOption &flags, MessageParcel &data, MessageParcel &reply)
{
    SLE_LOGD("InnerTransact In");
    auto remote = Remote();
    if (remote == nullptr) {
        SLE_LOGE("get remote failed, error code %{public}d", code);
        return OBJECT_NULL;
    }
    int32_t err = remote->SendRequest(code, data, reply, flags);
    if (err != NO_ERROR) {
        SLE_LOGE("send request failed, ipcErr=%{public}d code %{public}d", err, code);
    }
    return err;
}

SleErrorCode SleConnectProxy::RegisterConnectCallback(const sptr<ISleConnectCallback> &callback)
{
    SLE_LOGD("RegisterConnectCallback In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()),
        SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteRemoteObject(callback->AsObject()),
        SLE_ERR_IPC_TRANS_FAILED, "write announce callback failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_REGISTER_CONNECT_CALLBACK, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    return (SleErrorCode)reply.ReadInt32();
}

SleErrorCode SleConnectProxy::UnregisterConnectCallback(const sptr<ISleConnectCallback> &callback)
{
    SLE_LOGD("UnregisterConnectCallback In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteRemoteObject(callback->AsObject()), SLE_ERR_IPC_TRANS_FAILED, "write announce callback failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_UNREGISTER_CONNECT_CALLBACK, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    return (SleErrorCode)reply.ReadInt32();
}

SleErrorCode SleConnectProxy::Connect(const SleAddress &address)
{
    SLE_LOGD("Connect In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteParcelable(&address), SLE_ERR_IPC_TRANS_FAILED, "write address failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_CONNECT, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    return (SleErrorCode)reply.ReadInt32();
}

SleErrorCode SleConnectProxy::Disconnect(const SleAddress &address)
{
    SLE_LOGD("Disconnect In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteParcelable(&address), SLE_ERR_IPC_TRANS_FAILED, "write address failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_DISCONNECT, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    return (SleErrorCode)reply.ReadInt32();
}

SleErrorCode SleConnectProxy::GetConnectId(const SleAddress &address, uint16_t &connectId)
{
    SLE_LOGD("GetConnectId In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteParcelable(&address), SLE_ERR_IPC_TRANS_FAILED, "write address failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_GET_CONNECT_ID, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    int32_t exception = reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(exception == NO_ERROR, exception, "get connect id failed!(%d)", exception);
    connectId = reply.ReadUint16();
    return (SleErrorCode)exception;
}

SleErrorCode SleConnectProxy::GetConnectState(const SleAddress &address, int32_t &state)
{
    SLE_LOGD("GetConnectState In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteParcelable(&address), SLE_ERR_IPC_TRANS_FAILED, "write address failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_GET_CONNECT_STATE, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    int32_t exception = reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(exception == NO_ERROR, exception, "get connect state failed!(%d)", exception);
    state = reply.ReadInt32();
    return (SleErrorCode)exception;
}

SleErrorCode SleConnectProxy::GetConnectDeviceList(std::vector<SleConnectDevice> &devices, uint16_t &number)
{
    SLE_LOGD("GetConnectDeviceList In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_GET_CONNECT_DEVICE_LIST, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    int32_t exception = reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(exception == NO_ERROR, exception, "get connect device list failed!(%d)", exception);

    number = reply.ReadUint16();
    for (int i = 0; i < number; i++) {
        std::shared_ptr<SleConnectDevice> device(reply.ReadParcelable<SleConnectDevice>());
        if (!device) {
            return SLE_ERR_IPC_TRANS_FAILED;
        }
        devices.emplace_back(*device);
    }
    return (SleErrorCode)exception;
}

SleErrorCode SleConnectProxy::UpdateConnectParam(uint16_t connectId, const SleConnectionParam &param)
{
    SLE_LOGD("UpdateConnectParam In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteUint16(connectId), SLE_ERR_IPC_TRANS_FAILED, "write connect id failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteParcelable(&param), SLE_ERR_IPC_TRANS_FAILED, "write connect param failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_UPDATE_CONNECT_PARAM, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    return (SleErrorCode)reply.ReadInt32();
}

SleErrorCode SleConnectProxy::UpdateAllConnectParam(std::vector<SleConnectDevice> &successUpdateDevList, uint16_t &number)
{
    SLE_LOGD("UpdateAllConnectParam In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_UPDATE_ALL_CONNECT_PARAM, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    int32_t exception = 0;
    if (!reply.ReadInt32(exception)) {
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    if (!reply.ReadUint16(number)) {
        return SLE_ERR_IPC_TRANS_FAILED;
    }

    successUpdateDevList.clear();
    for (int i = 0; i < number; i++) {
        std::shared_ptr<SleConnectDevice> device(reply.ReadParcelable<SleConnectDevice>());
        if (!device) {
            return SLE_ERR_IPC_TRANS_FAILED;
        }
        successUpdateDevList.emplace_back(*device);
    }
    return (SleErrorCode)exception;
}

SleErrorCode SleConnectProxy::GetRecomSendDataSize(uint16_t connectId, uint32_t &recomSendDataSize)
{
    SLE_LOGD("GetRecomSendDataSize In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteUint16(connectId), SLE_ERR_IPC_TRANS_FAILED, "write connect id failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_GET_RECOM_SEND_DATA_SIZE, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    if (!reply.ReadUint32(recomSendDataSize)) {
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    return (SleErrorCode)reply.ReadInt32();
}

SleErrorCode SleConnectProxy::SendPairRequest(const SleAddress &address)
{
    SLE_LOGD("SendPairRequest In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteParcelable(&address), SLE_ERR_IPC_TRANS_FAILED, "write address failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_SEND_PAIR_REQUEST, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    return (SleErrorCode)reply.ReadInt32();
}

SleErrorCode SleConnectProxy::RemovePairedDevice(const SleAddress &address)
{
    SLE_LOGD("RemovePairedDevice In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteParcelable(&address), SLE_ERR_IPC_TRANS_FAILED, "write address failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_REMOVE_PAIRED_DEVICE, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    return (SleErrorCode)reply.ReadInt32();
}

SleErrorCode SleConnectProxy::RemoveAllPairedDevices()
{
    SLE_LOGD("RemovePairedDevice In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_REMOVE_ALL_PAIRED_DEVICES, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    return (SleErrorCode)reply.ReadInt32();
}

SleErrorCode SleConnectProxy::GetPairedDevicesNum(uint16_t &number)
{
    SLE_LOGD("RemovePairedDevice In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_GET_PAIRED_DEVICES_NUMBER, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    int32_t exception = reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(exception == NO_ERROR, exception, "get paired devices num failed!(%d)", exception);
    number = reply.ReadUint16();
    return (SleErrorCode)exception;
}

SleErrorCode SleConnectProxy::GetPairedDevices(std::vector<SleAddress> &devices, uint16_t &number)
{
    SLE_LOGD("GetPairedDevices In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_GET_PAIRED_DEVICES, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    int32_t exception = reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(exception == NO_ERROR, exception, "get paired devices failed!(%d)", exception);

    number = reply.ReadUint16();
    for (int i = 0; i < number; i++) {
        std::shared_ptr<SleAddress> device(reply.ReadParcelable<SleAddress>());
        if (!device) {
            return SLE_ERR_IPC_TRANS_FAILED;
        }
        devices.push_back(*device);
    }
    return (SleErrorCode)exception;
}

SleErrorCode SleConnectProxy::GetPairState(const SleAddress &address, uint8_t &state)
{
    SLE_LOGD("GetPairState In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteParcelable(&address), SLE_ERR_IPC_TRANS_FAILED, "write address failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_GET_PAIR_STATE, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    int32_t exception = reply.ReadInt32();
    SLE_ASSERT_AND_RETURN_RET_LOG(exception == NO_ERROR, exception, "get pair state failed!(%d)", exception);
    state = reply.ReadUint8();
    return (SleErrorCode)exception;
}

SleErrorCode SleConnectProxy::ReadRemoteRssi(uint16_t connectId)
{
    SLE_LOGD("ReadRemoteRssi In");
    MessageParcel data;
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteInterfaceToken(SleConnectProxy::GetDescriptor()), SLE_ERR_IPC_TRANS_FAILED, "write interface token failed!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.WriteUint16(connectId), SLE_ERR_IPC_TRANS_FAILED, "write connect id failed!");

    MessageParcel reply;
    MessageOption option = {MessageOption::TF_SYNC};
    int32_t result = InnerTransact(SleConnectInterfaceCode::SLE_READ_REMOTE_RSSI, option, data, reply);
    if (result != NO_ERROR) {
        SLE_LOGE("transact done fail, error code: %{public}d", result);
        return SLE_ERR_IPC_TRANS_FAILED;
    }
    return (SleErrorCode)reply.ReadInt32();
}
} // SleStandard
} // NearLink
} // OHOS